const Shape = require("./shape.js")
const Utils = require("./utils.js")
const {CN,EN,ClassMapping,PLUGINS,WEB} = require("./constant.js")

const ClassFactory = {
	[ClassMapping.linend]:require("./linend.js"),
	[ClassMapping.point]:require("./point.js"),
	[ClassMapping.curve]:require("./curve.js"),
	[ClassMapping.rect]:require("./rect.js"),
	[ClassMapping.circle]:require("./circle.js"),
	[ClassMapping.ellipse]:require("./ellipse.js"),
	[ClassMapping.arc]:require("./arc.js"),
	[ClassMapping.text]:require("./draw-text.js"),
	[ClassMapping.image]:require("./draw-img.js"),
	[ClassMapping.colorPicker]:require("./color-picker.js"),
	[ClassMapping.imagePicker]:require("./img-picker.js"),
	[ClassMapping.linePicker]:require("./line-picker.js"),
	[ClassMapping.polygon]:require("./polygon.js"),
	[ClassMapping.angle]:require("./angle.js"),

	[PLUGINS.number]:require("./number-input.js"),
	[PLUGINS.input]:require("./input-box.js")
}
module.exports = class DrawPanel extends Shape{
	constructor($env,$event){
		super($env,$event)
		
		let cvs=Utils.createDOM("canvas",{
			id:"draw-cvs",
			class:"draw-cvs"
		})
		let baseCvs = Utils.createDOM("canvas",{
			id:"ghost-cvs",
			class:"ghost-cvs"
		})

		this.cvs = cvs;
		this.baseCvs = baseCvs;

		this.resizeCanvas();

		this.ctx = this.$env.ctx = cvs.getContext("2d")
		this.$env.baseContext = baseCvs.getContext("2d");

		this.$event.emit(EN.append,cvs);
		this.$event.emit(EN.append,baseCvs);

		this.configCvs()

		this.__drawState={
			toolInstances:{}
		}
		this.$env.__steps = this.__steps
		this.bind()
	}
	bind(){
		window.addEventListener("resize",()=>{
			Utils.functional(this.$env,()=>{
				this.resizeCanvas()
				this.configCvs()
				this.rePaint()
			})
		})
		this.baseCvs.addEventListener("mousemove",(e)=>{
			if(this.__steps.length===0||!this.$env.currentTool)return

			var pos = this.cvsEvtPos({
					x : e.pageX,
			        y : e.pageY
			},this.cvs)
			this.baseCvs.classList[this.isInPath(pos.x,pos.y).length?"add":"remove"](CN.pointer)
		})
		this.$event.on(EN.img_done,(data)=>{
			this.createPlugin({
				name:ClassMapping.image,
				img:data
			})
		})
		this.$event.on(EN.action,(data)=>{
			this[data.name]&&this[data.name]()
		})
		this.$event.on(EN.plugin,(data)=>{
			this.createPlugin(data)
		})
		this.$event.on(EN.paint,(data)=>{
			this.initComponent(data)
		})
		this.$event.on("toggle-grid",(bg)=>{
			this.cvs.style.backgroundImage=`url(${bg})`
		})
		this.$event.on("line-pick",(data)=>{
			this.$env.lineDash = data;
			this.ctx.setLineDash(data);
			this.$env.baseContext.setLineDash(data)
		})
		this.$event.on("color:pick",(data)=>{
			this.$env.strokeStyle = data.c16
			this.$env.fillStyle = data.c16
			this.ctx.fillStyle=data.c16;
			this.ctx.strokeStyle=data.c16;
			this.$env.baseContext.fillStyle = data.c16;
			this.$env.baseContext.strokeStyle = data.c16;
		})

	}
	
	initComponent(data){
		let e = data.name;
		let currentTool = this.$env.currentTool;
		if(currentTool){
			currentTool.isActive = false;
			this.updatePlugins(currentTool.__relativePlugins||[],false)
		} 

		let instance = this.hasInstance(e);
		if(instance){
			this.updatePlugins(instance.__relativePlugins||[],true)
			return;
		}

		let cmp = this.createInstance(e)

		this.$env.currentTool = cmp;

		//记录绘画路径状态
		cmp.on(EN.update_state,(cmp,data)=>{
			this.updateSteps(cmp,data)
		})
	}
	updateSteps(cmp,data){
		this.__steps.push({
			cmp,data
		})
		this.updateCmpCount(cmp.name,1)
	}
	createPlugin(data){
		let name = data.name
		let plugin = this.hasPlugin(name);
		if(!plugin){
			let PluginClass = ClassFactory[name];
			plugin = new PluginClass(this.$env,this.$event,data)
			//记录绘画路径状态
			plugin.on&&plugin.on(EN.update_state,(cmp,data)=>{
				this.updateSteps(cmp,data)
			})
			this.__drawState.toolInstances[name]=plugin;
		}
		plugin.show(data)
	}
	createInstance(e){
		let CmpClass = ClassFactory[e];
		let cmp = new CmpClass(this.$env,this.$event)

		this.__drawState.toolInstances[e]=cmp;
		//是否关联另一个组件
		cmp.__relativePlugins&&cmp.__relativePlugins.forEach((plugin)=>{
			this.createPlugin(plugin)
		})
		if(cmp.name)// 初始化step计数器
		this.$env[e]=0
	
		return cmp;
	}
	hasPlugin(e){
		return this.__drawState.toolInstances[e];
	}
	hasInstance(e){
		let initialized = this.__drawState.toolInstances[e];
		if(initialized){
			this.$env.currentTool = initialized;
			initialized.isActive = true;
		}
		return initialized;
	}
	updatePlugins(plugins,isshow){
		if(plugins.length)
			plugins.forEach((plugin)=>this.__drawState.toolInstances[plugin.name][isshow?"show":"hide"](plugin));
	}
	clearRect(){
		this.ctx.clearRect(0,0,this.__setting.width,this.__setting.height)
	}
	undraw(){
		let step = this.__steps.pop();
		if(!step)return
		this.updateCmpCount(step.cmp.name,-1)
		this.rePaint()
	}
	clearState(){
		this.clearRect();
		for(let cname in this.__drawState.toolInstances)
			this.updateCmpCount(cname,0)
		this.__steps = [];
	}
	updateCmpCount(cname,oper){
		if(!cname)return;
		if(oper===0)
			this.$env[cname] = 0
		else   this.$env[cname] = this.$env[cname]+oper
	}
	
	rePaint(){
		this.clearRect();
		this.__steps.forEach((s)=>{
			this.ctx.save()
			s.cmp.rePaint(s.data)
			this.ctx.restore()
		})
	}
	resizeCanvas(){
		let {w,h} = this.documentRect()
		this.cvs.width = w;
		this.cvs.height = h;
		this.baseCvs.width = w;
		this.baseCvs.height = h;
		this.__setting = Utils.assign(this.__setting,{
			width:w,
			height:h
		})
		this.$event.emit("canvas-resize",w,h)
	}
	configCvs(){
		let $env = this.$env;
		let ctx = this.ctx
		let bc = this.$env.baseContext

		ctx.lineWidth = bc.lineWidth = $env.lineWidth;
		ctx.imageSmoothingEnabled = bc.imageSmoothingEnabled = true;
		// bc.shadowBlur=$env.shadowBlur;
		// bc.shadowColor=$env.shadowColor;
		ctx.fillStyle=bc.fillStyle = $env.fillStyle;
		ctx.strokeStyle=bc.strokeStyle = $env.strokeStyle;
		bc.setLineDash($env.lineDash);
		ctx.setLineDash($env.lineDash);
	}
}
